/**
 * Sep 17, 2013 4:55:03 PM
 * com.kratonsolution.belian.security.impl.dao
 * UserDaoImpl.java
 */
package com.kratonsolution.belian.security.impl.dao;

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.Query;
import org.springframework.stereotype.Component;

import com.kratonsolution.belian.common.util.Numbers;
import com.kratonsolution.belian.common.util.Paging;
import com.kratonsolution.belian.security.api.dao.SecurityDao;
import com.kratonsolution.belian.security.api.dao.UserDao;
import com.kratonsolution.belian.security.api.dm.User;

/**
 * @author Agung Dodi Perdana
 * @email agung.dodi.perdana@gmail.com
 * @Version Sinch 0.0.1
 */
@Component
public class UserDaoImpl extends SecurityDao implements UserDao
{
    private Logger log = Logger.getLogger(getClass());
    
    public User store(User model)
    {
        getSession().save(model);
        getSession().flush();
        return (User)model;
    }

    public User load(String id)
    {
        return (User)getSession().get(User.class, id);
    }

    public User loadByEmail(String email)
    {
        log.info("Object loaded with email ["+email+"]");
        Query query = getSession().createQuery("FROM User user WHERE user.email =:email ");
        query.setReadOnly(true);
        query.setCacheable(true);
        query.setParameter("email",email);
        
        User user = (User)query.uniqueResult();
        
        return user;
    }

    public User update(User model)
    {
        getSession().merge(model);
        return model;
    }

    public User remove(User model)
    {
        getSession().delete(model);
        return model;
    }

    public List<User> loads()
    {
        Query query = getSession().createQuery("FROM User user");
        query.setCacheable(true);
        
        return query.list();
    }

    public List<User> loads(Map<String, Object> param)
    {
        if(param == null || param.isEmpty())
            return loads();
        
        StringBuilder builder = new StringBuilder();
        builder.append("FROM User user WHERE user.id IS NOT NULL ");
        
        if(param.containsKey("email"))
            builder.append("AND user.email like :email ");
        
        if(param.containsKey("nickName"))
            builder.append("AND user.nickName like :nick ");
        
        builder.append(" ORDER BY user.email,user.nickName ASC ");
        
        Query query = getSession().createQuery(builder.toString());
        query.setCacheable(true);
        query.setFirstResult(Paging.getStart(param.get("start")));
        query.setMaxResults(Paging.getRowPerPage(param.get("max")));
        
        if(param.containsKey("email"))
            query.setParameter("email","%"+param.get("email")+"%");
        
        if(param.containsKey("nickName"))
            query.setParameter("nick", "%"+param.get("nickName")+"%");
        
        return query.list();
    }

    public long count()
    {
        return Numbers.toLong(getSession().createQuery("SELECT COUNT(user) FROM User user").uniqueResult());
    }

    public long count(Map<String, Object> param)
    {
        if(param != null && !param.isEmpty())
        {
            StringBuilder builder = new StringBuilder();
            builder.append("SELECT COUNT(user) FROM User user WHERE user.id IS NOT NULL ");
            
            if(param.containsKey("email"))
                builder.append("AND user.email like :email ");
            
            if(param.containsKey("nickName"))
                builder.append("AND user.nickName like :nick ");
            
            builder.append(" ORDER BY user.email,user.nickName ASC ");
            
            Query query = getSession().createQuery(builder.toString());
            query.setCacheable(true);
            
            if(param.containsKey("email"))
                query.setParameter("email","%"+param.get("email")+"%");
            
            if(param.containsKey("nickName"))
                query.setParameter("nick", "%"+param.get("nickName")+"%");
            
            return Numbers.toLong(query.uniqueResult());
        }
        
        return 0l;
    }
}
